package com.philosophy.web.filter;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import com.philosophy.web.domain.generate.UrlMapping;
import com.philosophy.web.event.LoadEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @author philosophy
 */
@SuppressWarnings("all")
@Component
@Slf4j
public class RedirectFilter implements ApplicationEventPublisherAware, CommandLineRunner {
    /**
     * 期望的误判率
     */
    private static final double FPP = 0.0001;

    /**
     * 预估元素个数
     */
    private static final int EXPECTED_INSERTIONS = 100000000;

    private ApplicationEventPublisher applicationEventPublisher;

    private final BloomFilter<String> bloomFilter = createBloomFilter(EXPECTED_INSERTIONS);

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * 加载url_mapping到bloomFilter
     */
    @Override
    public void run(String... args) throws Exception {
        this.applicationEventPublisher.publishEvent(new LoadEvent(this));
        log.info("=============加载数据事发布成功!");
    }

    public boolean isExistShortUrl(String shortUrl) {
        return bloomFilter.mightContain(shortUrl);
    }

    public void putBloomFilter(String shortUrl) {
        bloomFilter.put(shortUrl);
    }


    /**
     * <p>
     * 1:加载数据到布隆过滤器
     * </p>
     *
     * @param urlMappings urlMappings
     * @param bloomFilter bloomFilter
     */
    public static void loadBloomFilter(List<UrlMapping> urlMappings, BloomFilter<String> bloomFilter) {
        if (CollectionUtils.isEmpty(urlMappings)) {
            return;
        }
        for (UrlMapping urlMapping : urlMappings) {
            bloomFilter.put(urlMapping.getShortUrl());
        }
    }

    /**
     * 创建布隆过滤器
     *
     * @return BloomFilter
     */
    public static BloomFilter<String> createBloomFilter(long expectedInsertions) {
        return BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), expectedInsertions, FPP);
    }
}
